package com.wuyan.web.form.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wuyan.helper.kit.DateHelper;
import com.wuyan.web.base.helper.auth.LoginInfo;
import com.wuyan.web.base.helper.mongo.MongodbHelper;
import com.wuyan.web.base.helper.rep.RepPageData;
import com.wuyan.web.base.helper.req.CustomQueryOrderParams;
import com.wuyan.web.base.helper.req.CustomQueryParams;
import com.wuyan.web.form.entity.PubForm;
import com.wuyan.web.form.helper.FormHelper;
import com.wuyan.web.form.helper.WordStorageHelper;
import com.wuyan.web.form.helper.WordStoragePathTypeEnum;
import com.wuyan.web.form.repo.PubFormRepo;
import com.wuyan.web.form.service.api.WuyanPubMsgApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class FormService {

    public static final String DEF_CREATE_TIME_NAME = "create_time";
    public static final String DEF_OPERATE_TIME_NAME = "operate_time";
    public static final String DEF_CFG_STATUS_NAME = "cfg_status";
    public static final String DEF_CFG_STATUS_NAME_NAME = "cfg_status_name";
    public static final String DEF_CFG_SOURCE_NAME = "cfg_source";
    public static final String DEF_CREATOR_ID_NAME = "creator_id";
    public static final String DEF_CREATOR_NAME_NAME = "creator_name";
    public static final String DEF_CFG_FLOW_ID_NAME = "cfg_flow_id";
    public static final String DEF_CFG_ACTIVE_NAME = "cfg_active";
    public static final String DEF_CFG_FINISH_NAME = "cfg_finish";
    public static final String DEF_ID_NAME = "id";
    public static final String DEF_MONGO_ID_NAME = "_id";
    public static final String DEF_PARENT_ID_NAME = "parent_id";

    /**
     * 分词存储的表的前缀
     */
    public static final String DEF_WORD_TABLE_NAME = "word_";

    @Autowired
    private WordStorageHelper wordStorageHelper;

    @Autowired
    private MongodbHelper mongodbHelper;

    @Autowired
    private PubFormRepo pubFormRepo;

    @Autowired
    private FlowService flowService;

    @Autowired
    private FormHelper formHelper;

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private WuyanPubMsgApiService wuyanPubMsgApiService;

    /**
     * 创建文档
     *
     * @param table     集合名
     * @param form      文档数据
     * @param loginInfo 登录信息
     * @return Map<String, Object>
     */
    public Map<String, Object> create(String table, Map<String, Object> form,
                                      LoginInfo loginInfo, PubForm pubForm) throws Exception {
        form.put(DEF_CREATE_TIME_NAME, DateHelper.get());
        form.put(DEF_OPERATE_TIME_NAME, DateHelper.get());

        if (null == form.get(DEF_CFG_SOURCE_NAME) || StringUtils.isBlank(form.get(DEF_CFG_SOURCE_NAME).toString())) {
            form.put(DEF_CFG_SOURCE_NAME, "create");
        }

        if (null == form.get(DEF_CFG_STATUS_NAME) || StringUtils.isBlank(form.get(DEF_CFG_STATUS_NAME).toString())) {
            form.put(DEF_CFG_STATUS_NAME, "0");
        }

        form.putIfAbsent(DEF_CFG_FINISH_NAME, false);

        form.put(DEF_CREATOR_ID_NAME, null == loginInfo ? 0 : loginInfo.getAccount().getId());
        form.put(DEF_CREATOR_NAME_NAME, null == loginInfo
                ? ""
                : StringUtils.isBlank(loginInfo.getUser().getNickname())
                ? loginInfo.getAccount().getUsername()
                : loginInfo.getUser().getNickname());

        // 处理流程绑定|因为ID是由mongo生成，因此不会是全数字
        if (StringUtils.isNotBlank(pubForm.getFlowId()) && !StringUtils.isNumericSpace(pubForm.getFlowId())) {
            form.put(DEF_CFG_FLOW_ID_NAME, pubForm.getFlowId());
            form = flowService.create(form, loginInfo);
        }

        // 对于已经携带ID的条目，直接使用该id作为唯一标识
        if (form.containsKey(DEF_ID_NAME)) {
            form.put(DEF_MONGO_ID_NAME, form.get(DEF_ID_NAME));
            form.remove(DEF_ID_NAME);
        }

        Map<String, Object> save = mongodbHelper.save(form, table);

        Map<String, Object> update = new HashMap<>();

        // 分词存储
        if (wordStorageHelper.getWord()) {
            Map<String, Object> wordData = wordStorageHelper.word(save);

            // 独立存储判断
            if (wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.NEW || wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.ALL) {
                String wordTable = DEF_WORD_TABLE_NAME + table;

                if (wordData.containsKey(DEF_ID_NAME)) {
                    wordData.put(DEF_PARENT_ID_NAME, wordData.get(DEF_ID_NAME));
                    wordData.remove(DEF_ID_NAME);
                }

                mongodbHelper.save(wordData, wordTable);
            }

            // 本地存储判断
            if (wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.LOCAL || wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.ALL) {
                update.put(WordStorageHelper.WORD_TAGS_NAME, wordData.get(WordStorageHelper.WORD_TAGS_NAME));
            }
        }

        // 全文检索
        if (wordStorageHelper.getFullText()) {
            wordStorageHelper.fullText(save);
            update.put(WordStorageHelper.FULL_TEXT_NAME, save.get(WordStorageHelper.FULL_TEXT_NAME));
        }

        // 更新数据
        if (wordStorageHelper.getWord() || wordStorageHelper.getFullText()) {
            update(save.get(DEF_ID_NAME).toString(), table, update);
        }

        updateFormDataCount(pubForm, 1);

        sendMsg(loginInfo, pubForm, save);

        return save;
    }

    public long update(String id, String table, Map<String, Object> form) {
        form.put(DEF_OPERATE_TIME_NAME, DateHelper.get());

        Map<String, Object> params = new HashMap<>();
        params.put(DEF_MONGO_ID_NAME, id);

        return mongodbHelper.updateFirst(params, form, table);
    }

    public long delete(String[] id, String table, PubForm pubForm) {
        List<CustomQueryParams> params = new ArrayList<>();
        params.add(CustomQueryParams.builder()
                .left(DEF_MONGO_ID_NAME)
                .op("in")
                .right(id)
                .build());

        long remove = mongodbHelper.remove(params, table);

        // 移除分词数据
        List<CustomQueryParams> wordParams = new ArrayList<>();
        wordParams.add(CustomQueryParams.builder()
                .left(DEF_PARENT_ID_NAME)
                .op("in")
                .right(id)
                .build());
        String wordTable = DEF_WORD_TABLE_NAME + table;

        mongodbHelper.remove(wordParams, wordTable);

        updateFormDataCount(pubForm, -1);

        return remove;
    }

    /**
     * 查询功能
     *
     * @param table      集合名
     * @param isPage     是否执行分页
     * @param page       当前页，当且仅当siPage为true时有效
     * @param limit      每页的大小，当且仅当siPage为true时有效
     * @param paramsList 查询条件
     * @param orderList  排序条件
     * @return RepPageData<Map>
     */
    public RepPageData<Map> page(String table,
                                 Boolean isPage, Integer page, Integer limit,
                                 List<CustomQueryParams> paramsList,
                                 List<CustomQueryOrderParams> orderList) {
        List<Map> list;
        long count;

        /*
            查询时需要判断查询位置，优先匹配同级存储模式
         */
        if (wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.LOCAL
                || wordStorageHelper.getWordSavePath() == WordStoragePathTypeEnum.ALL) {
            list = mongodbHelper.find(paramsList, orderList, Map.class, table, isPage, page, limit);
            count = mongodbHelper.count(paramsList, orderList, Map.class, table);
        } else {
            String wordTable = DEF_WORD_TABLE_NAME + table;
            // 先找到索引区
            List<Map> indexList = mongodbHelper.find(new String[]{DEF_PARENT_ID_NAME}, paramsList, orderList, Map.class, wordTable, isPage, page, limit);
            if (null == indexList || indexList.size() < 1) {
                return RepPageData.<Map>builder()
                        .list(indexList)
                        .page(1)
                        .limit(limit)
                        .count(0)
                        .build();
            }

            // 再找主区
            List<CustomQueryParams> paramsMain = new ArrayList<>();
            paramsMain.add(CustomQueryParams.builder()
                    .left(DEF_MONGO_ID_NAME)
                    .op("in")
                    .right(indexList.stream().map(t -> t.get(DEF_PARENT_ID_NAME)).toArray())
                    .build());
            list = mongodbHelper.find(paramsMain, orderList, Map.class, table);
            count = mongodbHelper.count(paramsList, orderList, Map.class, wordTable);
        }

        return RepPageData.<Map>builder()
                .list(list)
                .page(1)
                .limit(limit)
                .count(count)
                .build();
    }

    public Map get(String id, String table) {
        return mongodbHelper.findOne(id, Map.class, table);
    }

    /**
     * 更新表单数据总量
     *
     * @param pubForm 表单信息
     * @param add     新增加的量
     */
    private void updateFormDataCount(PubForm pubForm, int add) {
        Integer dataCount = pubForm.getDataCount();
        if (null != dataCount && dataCount + add < 0) {
            return;
        }

        pubForm.setDataCount(null == dataCount ? add : (dataCount + add));
        pubFormRepo.save(pubForm);

    }

    /**
     * 为指定集合建立全文索引.
     *
     * @param table 集合
     * @return boolean
     */
    public boolean ensureIndexFullText(String table) {
        return mongodbHelper.createFullText(table);
    }

    /**
     * 发送通知消息
     *
     * @param loginInfo 登录账户信息
     * @param pubForm   表单信息
     * @param data      数据
     */
    private void sendMsg(LoginInfo loginInfo, PubForm pubForm, Map<String, Object> data) {
        List<String> configs = formHelper.getAddNotifyByFormId(pubForm.getId());

        configs.forEach(value -> {
            if (StringUtils.isBlank(value)) {
                return;
            }

            try {
                JsonNode config = mapper.readTree(value);
                Integer fromDept = config.get("from").asInt();
                Integer toDept = config.get("to").asInt();

                // 部门不匹配，忽略
                if(!fromDept.equals(loginInfo.getDept().getId())){
                    return;
                }

                wuyanPubMsgApiService.createDeptNotify(toDept,
                        data.get(DEF_ID_NAME).toString(),
                        "连部通知");
            } catch (JsonProcessingException e) {
                log.error(e.getMessage(), e);
            }
        });


    }
}
